package com.lxk.ums.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lxk.ums.domain.UmsUser;
import com.lxk.ums.domain.bo.UmsUserBo;
import com.lxk.ums.domain.vo.UmsUserVo;
import com.lxk.ums.mapper.UmsUserMapper;
import com.lxk.ums.service.IUmsUserService;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.BeanCopyUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户Service业务层处理
 *
 * @author LXK-RY5
 * @date 2024-06-27
 */
@RequiredArgsConstructor
@Service
public class UmsUserServiceImpl implements IUmsUserService {

    private final UmsUserMapper baseMapper;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public UmsUserVo registerUserByPhone(String phone,
                                                   String userType,
                                                   String inviteCode,
                                         String registerDeviceType,
                                         String xcxOpenId,
                                         String unionId
    ) {
        Assert.notBlank(phone);
        Assert.notBlank(userType);
        UmsUserBo add = new UmsUserBo();
        add.setWxMiniAppOpenId(xcxOpenId);
        add.setWxUnionidId(unionId);
        add.setUserName(phone);
        add.setPhonenumber(phone);
        add.setUserType(userType);
        add.setNickName("游客" + RandomUtil.randomString(6));
        add.setUserSn(IdUtil.getSnowflakeNextIdStr());
        add.setInviterCode(inviteCode);
        add.setRegisterDeviceType(StrUtil.isNotBlank(registerDeviceType) ? registerDeviceType.toLowerCase() : null);
        this.insertByBo(add);
        UmsUserVo umsUserVo = BeanCopyUtils.copy(add, UmsUserVo.class);
        return umsUserVo;
    }

    @Override
    public UmsUserVo registerUserByPhone(String phone,
                                         String password,
                                         String userType,
                                         String inviteCode,
                                         String registerDeviceType,
                                         String xcxOpenId,
                                         String unionId) {
        Assert.notBlank(phone);
        Assert.notBlank(password);
        Assert.notBlank(userType);
        UmsUserBo add = new UmsUserBo();
        add.setWxMiniAppOpenId(xcxOpenId);
        add.setWxUnionidId(unionId);
        add.setUserName(phone);
        add.setPassword(password);
        add.setPhonenumber(phone);
        add.setUserType(userType);
        add.setNickName("游客" + RandomUtil.randomString(6));
        add.setUserSn(IdUtil.getSnowflakeNextIdStr());
        add.setInviterCode(inviteCode);
        add.setRegisterDeviceType(StrUtil.isNotBlank(registerDeviceType) ? registerDeviceType.toLowerCase() : null);
        this.insertByBo(add);
        UmsUserVo umsUserVo = BeanCopyUtils.copy(add, UmsUserVo.class);
        return umsUserVo;
    }

    @Override
    public Opt<UmsUserVo> queryByPhone(String phone) {
        LambdaQueryWrapper<UmsUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(UmsUser::getPhonenumber, phone);
        UmsUserVo umsUserVo = baseMapper.selectVoOne(lqw, false);
        return Opt.ofNullable(umsUserVo);
    }

    /**
     * 查询IdList用户Map
     */
    @Override
    public Map<Long, UmsUserVo> queryMapByIdList(List<Long> idList) {
        return this.queryByIdList(idList).stream().collect(Collectors.toMap(UmsUserVo::getId, v -> v));
    }

    /**
     * 查询用户Map
     */
    @Override
    public Map<Long, UmsUserVo> queryMap(UmsUserBo bo) {
        return this.queryList(bo).stream().collect(Collectors.toMap(UmsUserVo::getId, v -> v));
    }

    /**
     * 查询用户IdList
     */
    @Override
    public List<UmsUserVo> queryByIdList(List<Long> idList) {
        if (CollUtil.isEmpty(idList)) {
            return CollUtil.newArrayList();
        }
        LambdaQueryWrapper<UmsUser> lqw = Wrappers.lambdaQuery();
        lqw.in(UmsUser::getId, idList);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 查询用户
     *
     * @param id 主键
     * @return 用户
     */
    @Override
    public UmsUserVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询用户列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 用户分页列表
     */
    @Override
    public TableDataInfo<UmsUserVo> queryPageList(UmsUserBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<UmsUser> lqw = buildQueryWrapper(bo);
        Page<UmsUserVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的用户列表
     *
     * @param bo 查询条件
     * @return 用户列表
     */
    @Override
    public List<UmsUserVo> queryList(UmsUserBo bo) {
        LambdaQueryWrapper<UmsUser> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<UmsUser> buildQueryWrapper(UmsUserBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<UmsUser> lqw = Wrappers.lambdaQuery();
        lqw.orderByDesc(UmsUser::getId);
        lqw.like(StringUtils.isNotBlank(bo.getUserName()), UmsUser::getUserName, bo.getUserName());
        lqw.like(StringUtils.isNotBlank(bo.getNickName()), UmsUser::getNickName, bo.getNickName());
        lqw.eq(StringUtils.isNotBlank(bo.getUserType()), UmsUser::getUserType, bo.getUserType());
        lqw.eq(StringUtils.isNotBlank(bo.getIntroduce()), UmsUser::getIntroduce, bo.getIntroduce());
        lqw.eq(StringUtils.isNotBlank(bo.getEmail()), UmsUser::getEmail, bo.getEmail());
        lqw.eq(StringUtils.isNotBlank(bo.getPhonenumber()), UmsUser::getPhonenumber, bo.getPhonenumber());
        lqw.eq(StringUtils.isNotBlank(bo.getSex()), UmsUser::getSex, bo.getSex());
        lqw.eq(StringUtils.isNotBlank(bo.getAvatar()), UmsUser::getAvatar, bo.getAvatar());
        lqw.eq(StringUtils.isNotBlank(bo.getPassword()), UmsUser::getPassword, bo.getPassword());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), UmsUser::getStatus, bo.getStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getLoginIp()), UmsUser::getLoginIp, bo.getLoginIp());
        lqw.eq(bo.getLoginDate() != null, UmsUser::getLoginDate, bo.getLoginDate());
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
            UmsUser::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
        lqw.eq(StringUtils.isNotBlank(bo.getWxAppOpenId()), UmsUser::getWxAppOpenId, bo.getWxAppOpenId());
        lqw.eq(StringUtils.isNotBlank(bo.getWxUnionidId()), UmsUser::getWxUnionidId, bo.getWxUnionidId());
        lqw.eq(StringUtils.isNotBlank(bo.getWxMiniAppOpenId()), UmsUser::getWxMiniAppOpenId, bo.getWxMiniAppOpenId());
        lqw.eq(StringUtils.isNotBlank(bo.getWxMpAppOpenId()), UmsUser::getWxMpAppOpenId, bo.getWxMpAppOpenId());
        lqw.eq(StringUtils.isNotBlank(bo.getWxPcOpenId()), UmsUser::getWxPcOpenId, bo.getWxPcOpenId());
        lqw.eq(StringUtils.isNotBlank(bo.getUserSn()), UmsUser::getUserSn, bo.getUserSn());
        lqw.eq(StringUtils.isNotBlank(bo.getInviterCode()), UmsUser::getInviterCode, bo.getInviterCode());
        lqw.eq(StringUtils.isNotBlank(bo.getRegisterDeviceType()), UmsUser::getRegisterDeviceType, bo.getRegisterDeviceType());
        return lqw;
    }

    /**
     * 新增用户
     *
     * @param bo 用户
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(UmsUserBo bo) {
        UmsUser add = MapstructUtils.convert(bo, UmsUser.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改用户
     *
     * @param bo 用户
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(UmsUserBo bo) {
        UmsUser update = MapstructUtils.convert(bo, UmsUser.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(UmsUser entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除用户信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public UmsUserVo getUserByMobile(String userMobile) {
        if (StrUtil.isBlank(userMobile)) {
            return null;
        }
        LambdaQueryWrapper<UmsUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(UmsUser::getPhonenumber, userMobile);
        lqw.last("limit 1");
        return baseMapper.selectVoOne(lqw);
    }

    @Override
    public Opt<UmsUserVo> getUserByUserName(String userName) {
        if (StrUtil.isBlank(userName)) {
            return null;
        }
        LambdaQueryWrapper<UmsUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(UmsUser::getUserName, userName);
        return Opt.ofNullable(baseMapper.selectVoOne(lqw,false));
    }

    @Override
    public List<UmsUserVo> getUserListByNickname(String userNickname) {
        if (StrUtil.isBlank(userNickname)) {
            return List.of();
        }
        LambdaQueryWrapper<UmsUser> lqw = Wrappers.lambdaQuery();
        lqw.like(UmsUser::getNickName, userNickname);
        return baseMapper.selectVoList(lqw);
    }

    @Override
    public Opt<UmsUserVo> queryByOpenId(String openid) {
        LambdaQueryWrapper<UmsUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(UmsUser::getWxMiniAppOpenId, openid);
        UmsUserVo umsUserVo = baseMapper.selectVoOne(lqw, false);
        return Opt.ofNullable(umsUserVo);
    }

    @Override
    public UmsUserVo registerUserByOpenId(String openid, String phoneNumber, String userType, String inviterCode, String registerDeviceType) {
        Assert.notBlank(openid);
        Assert.notBlank(userType);
        UmsUserBo add = new UmsUserBo();
        add.setUserName(phoneNumber);
        add.setPhonenumber(phoneNumber);
        add.setUserType(userType);
        add.setWxMiniAppOpenId(openid);
        add.setNickName("游客" + RandomUtil.randomString(6));
        add.setUserSn(IdUtil.getSnowflakeNextIdStr());
        add.setInviterCode(inviterCode);
        add.setRegisterDeviceType(StrUtil.isNotBlank(registerDeviceType) ? registerDeviceType.toLowerCase() : null);
        this.insertByBo(add);
        UmsUserVo umsUserVo = BeanCopyUtils.copy(add, UmsUserVo.class);
        return umsUserVo;
    }
}
